home *** CD-ROM | disk | FTP | other *** search
/ BCI NET 2 / BCI NET 2.iso / archives / programming / languages / obrn-a_1.5_lib.lha / oberon-a / source2.lha / Source / Kernel / Kernel.mod < prev    next >
Encoding:
Text File  |  1995-01-26  |  41.8 KB  |  1,316 lines

  1. (**************************************************************************
  2.  
  3.      $RCSfile: Kernel.mod $
  4.   Description: Oberon-A run-time support module.
  5.  
  6.    Created by: fjc (Frank Copeland)
  7.     $Revision: 1.5 $
  8.       $Author: fjc $
  9.         $Date: 1995/01/26 00:37:31 $
  10.  
  11.   Copyright © 1994-1995, Frank Copeland.
  12.   This file is part of Oberon-A.
  13.   See Oberon-A.doc for conditions of use and distribution.
  14.  
  15.   Log entries are at the end of the file.
  16.   ________________________________________________________________________
  17.  
  18.   This module has a special status in the Oberon-A system. It is always
  19.   included in a program, even if no other module imports it. It is
  20.   *always* the first module that gets initialised at run-time, and it is
  21.   responsible for cleaning up the program's environment before it exits.
  22.   Procedures in this module are called directly by the compiler to
  23.   perform operations that are too complex to be coded inline.
  24.  
  25.   Assumptions about this module are hard-coded into the compiler, and you
  26.   change it at your peril. Those elements that must NOT be changed will
  27.   be clearly indicated in the associated commentary. The remaining
  28.   elements may be modified, but you must do so with extreme care.
  29.  
  30.   This module must be a leaf module. That is, it must not import from any
  31.   other module except SYSTEM. Any access to Amiga system software *must*
  32.   be through variables and types declared in this module.
  33.  
  34. **************************************************************************)
  35.  
  36. <* STANDARD- *> <* MAIN- *> <* INITIALISE- *>
  37.  
  38. (* Turn off ALL compiler checks. *)
  39.  
  40. <*$ CaseChk- IndexChk- NilChk- RangeChk- StackChk- TypeChk- OvflChk- *>
  41.  
  42. (* Create selector for a debugging version *)
  43.  
  44. <* NEW DEBUG1 *> <* DEBUG1- *> (* Disabled *)
  45.  
  46. <* IF DEBUG1 THEN *>
  47. MODULE Kernel ["LMath.o", "MarkDbg.o"];
  48. <* ELSE *>
  49. MODULE Kernel ["LMath.o", "Mark.o"];
  50. <* END *>
  51.  
  52. IMPORT SYS := SYSTEM;
  53.  
  54.  
  55. (*-----------------------------------------------------------------------**
  56. ** The following declarations duplicate those in modules Exec and Dos,   **
  57. ** so that there is no need to import those modules.                     **
  58. **-----------------------------------------------------------------------*)
  59.  
  60.  
  61. CONST
  62.  
  63.   memAny       = {};
  64.   memPublic    = 0;
  65.   memChip      = 1;
  66.   memFast      = 2;
  67.   memLocal     = 8;
  68.   mem24BitDMA  = 9;
  69.   memKick      = 10;
  70.  
  71.   memClear     = 16;
  72.   memLargest   = 17;
  73.   memReverse   = 18;
  74.   memTotal     = 19;
  75.  
  76.   memNoExpunge = 31;
  77.  
  78. TYPE
  79.  
  80.   LibraryPtr = POINTER [1] TO Library;
  81.   Library = RECORD [1] END;
  82.   ExecBasePtr = POINTER [1] TO ExecBase;
  83.   ExecBase = RECORD [1] (Library) END;
  84.   PROC = PROCEDURE;
  85.   STRPTR = POINTER [1] TO ARRAY 32767 OF CHAR;
  86.   BSET = SYS.BYTESET;
  87.   WSET = SYS.WORDSET;
  88.   APTR = SYS.ADDRESS;
  89.   UBYTE = SYS.BYTE;
  90.  
  91.   MinNodePtr = POINTER [1] TO MinNode;
  92.   MinNode = RECORD [1]
  93.     succ : MinNodePtr;
  94.     pred : MinNodePtr;
  95.   END;
  96.  
  97.   Node = RECORD [1] (MinNode)
  98.     type : UBYTE;
  99.     pri  : SHORTINT;
  100.     name : STRPTR;
  101.   END;
  102.  
  103.   MinList = RECORD [1]
  104.     head     : MinNodePtr;
  105.     tail     : MinNodePtr;
  106.     tailPred : MinNodePtr;
  107.   END;
  108.  
  109.   List = RECORD [1] (MinList)
  110.    type     : UBYTE;
  111.    pad      : UBYTE;
  112.   END;
  113.  
  114.   TaskPtr = POINTER [1] TO Task;
  115.   Task = RECORD [1] (Node)
  116.     tcFlags    : BSET;
  117.     state      : BSET;
  118.     idNestCnt  : SHORTINT;
  119.     tdNestCnt  : SHORTINT;
  120.     sigAlloc   : SET;
  121.     sigWait    : SET;
  122.     sigRecvd   : SET;
  123.     sigExcept  : SET;
  124.     trapAlloc  : WSET;
  125.     trapAble   : WSET;
  126.     exceptData : APTR;
  127.     exceptCode : PROC;
  128.     trapData   : APTR;
  129.     trapCode   : PROC;
  130.     spReg      : APTR;
  131.     spLower    : APTR;
  132.     spUpper    : APTR;
  133.     switch     : PROC;
  134.     launch     : PROC;
  135.     memEntry   : List;
  136.     userData   : APTR;
  137.   END;
  138.  
  139.   MsgPort = RECORD [1] (Node)
  140.     mpFlags : BSET;
  141.     sigBit  : SHORTINT;
  142.     sigTask : TaskPtr;
  143.     msgList : List;
  144.   END;
  145.  
  146.   ProcessPtr = POINTER [1] TO Process;
  147.   Process = RECORD [1] (Task)
  148.     msgPort        : MsgPort;
  149.     pad            : INTEGER;
  150.     segList        : SYS.BPTR;
  151.     stackSize      : LONGINT;
  152.     globVec        : APTR;
  153.     taskNum        : LONGINT;
  154.     stackBase      : SYS.BPTR;
  155.     result2        : LONGINT;
  156.     currentDir     : SYS.BPTR;
  157.     cis            : SYS.BPTR;
  158.     cos            : SYS.BPTR;
  159.     consoleTask    : APTR;
  160.     fileSystemTask : APTR;
  161.     cli            : SYS.BPTR;
  162.     returnAddr     : APTR;
  163.     pktWait        : APTR;
  164.     windowPtr      : APTR;
  165.     homeDir        : SYS.BPTR;
  166.     prFlags        : SET;
  167.     exitCode       : PROC;
  168.     exitData       : LONGINT;
  169.     arguments      : STRPTR;
  170.     localVars      : MinList;
  171.     shellPrivate   : LONGINT;
  172.     ces            : SYS.BPTR;
  173.   END;
  174.  
  175.  
  176. (*-----------------------------------------------------------------------**
  177. **              System library bases used by this module.                **
  178. **-----------------------------------------------------------------------*)
  179.  
  180. CONST
  181.  
  182.   AbsExecBase = 4;
  183.  
  184. VAR
  185.  
  186.   SysBase  : ExecBasePtr;  (* Used to access exec.library functions *)
  187.  
  188.   mathBase : LibraryPtr;   (* Base pointer for math#?.library. This is
  189.                            ** used for all REAL arithmetic.
  190.                            *)
  191.  
  192.  
  193. (*-----------------------------------------------------------------------**
  194. ** These variables are used to remember the programs initial state, so   **
  195. ** that it can be restored on exit. Do NOT make them writeable.          **
  196. **-----------------------------------------------------------------------*)
  197.  
  198. VAR
  199.  
  200.   initialSP   : LONGINT;      (* Initial contents of A7. *)
  201.  
  202.  
  203. (*-----------------------------------------------------------------------**
  204. ** These variables are used to hold the arguments passed to the program  **
  205. ** by AmigaDOS or Workbench. Do NOT make them writeable.                 **
  206. **-----------------------------------------------------------------------*)
  207.  
  208. VAR
  209.  
  210.   fromWorkbench -: BOOLEAN;
  211.                            (* TRUE if the program was started from
  212.                            ** Workbench, FALSE if it was started by a
  213.                            ** Shell or CLI.
  214.                            *)
  215.  
  216.   dosCmdBuf     -: SYS.ADDRESS;
  217.                            (* When started from a Shell or CLI, this
  218.                            ** variable will hold the command line used to
  219.                            ** run the program. Only valid if
  220.                            ** fromWorkbench is FALSE.
  221.                            *)
  222.  
  223.   dosCmdLen     -: LONGINT;
  224.                            (* The length in characters of the command
  225.                            ** line. Only valid if fromWorkbench is FALSE.
  226.                            *)
  227.  
  228.   WBenchMsg     -: SYS.ADDRESS;
  229.                            (* The startup message sent to the program by
  230.                            ** Workbench. Only valid if fromWorkbench is
  231.                            ** TRUE. This must be cast to a
  232.                            ** Workbench.WBStartupPtr to gain access to
  233.                            ** the arguments.
  234.                            *)
  235.  
  236.  
  237. (*-----------------------------------------------------------------------**
  238. ** The following declarations are used by the memory allocator and the   **
  239. ** garbage collector. DO NOT CHANGE THEM. See Memory.txt for a           **
  240. ** discussion of their use.                                              **
  241. **-----------------------------------------------------------------------*)
  242.  
  243. <* IF DEBUG1 THEN *>
  244.   CONST
  245.     RecordBlkId = 052424C4BH; (* "RBLK" *)
  246.     ArrayBlkId  = 041424C4BH; (* "ABLK" *)
  247.     SysBlkId    = 053424C4BH; (* "SBLK" *)
  248. <* END *>
  249.  
  250. TYPE
  251.  
  252.   RecordBlkPtr = POINTER [1] TO RecordBlk;
  253.   RecordBlk = RECORD [1]
  254.     link : SYS.ADDRESS;
  255.     <* IF DEBUG1 THEN *>
  256.     id   : LONGINT;
  257.     <* END *>
  258.     tag  : SYS.TYPETAG;
  259.   END; (* RecordBlk *)
  260.  
  261.   ArrayBlkPtr = POINTER [1] TO ArrayBlk;
  262.   ArrayBlk = RECORD [1]
  263.     arrPos   : LONGINT;
  264.     elemSize : LONGINT;
  265.     size     : LONGINT;
  266.     link     : SYS.ADDRESS;
  267.     <* IF DEBUG1 THEN *>
  268.     id       : LONGINT;
  269.     <* END *>
  270.     tag      : SYS.TYPETAG;
  271.   END;
  272.  
  273.   SysBlkPtr = POINTER [1] TO SysBlk;
  274.   SysBlk = RECORD [1]
  275.     link : SYS.ADDRESS;
  276.     <* IF DEBUG1 THEN *>
  277.     id   : LONGINT;
  278.     <* END *>
  279.     size : LONGINT;
  280.   END; (* SysBlk *)
  281.  
  282.   MemBlockPtr = POINTER [1] TO MemBlock;
  283.   MemBlock = RECORD [1]
  284.     link    : MemBlockPtr;
  285.     <* IF DEBUG1 THEN *>
  286.     id      : LONGINT;
  287.     <* END *>
  288.     sizeTag : SET;
  289.   END;
  290.  
  291.   GCOffsetPtr = POINTER [1] TO GCOffsetBlock;
  292.   GCOffsetBlock = RECORD [1]
  293.     link    : GCOffsetPtr;
  294.     varBase : SYS.ADDRESS;
  295.   (*offsets : ARRAY OF LONGINT;*)
  296.   END; (* GCOffsetBlock *)
  297.  
  298.  
  299. (*-----------------------------------------------------------------------**
  300. ** The compiler uses the type descriptor for the following type when     **
  301. ** allocating arrays of pointers with NEW. This MUST be the first tagged **
  302. ** type declared in this module. It should also be the only one.         **
  303. **-----------------------------------------------------------------------*)
  304.  
  305. TYPE
  306.  
  307.   PointerDesc = RECORD
  308.     ptr : SYS.PTR
  309.   END; (* PointerDesc *)
  310.  
  311.  
  312. (*-----------------------------------------------------------------------**
  313. ** These variables are used by the memory allocator and the garbage      **
  314. ** collector.                                                            **
  315. **-----------------------------------------------------------------------*)
  316.  
  317. VAR
  318.  
  319.   gcBase   : SYS.ADDRESS;  (* The root of the list of variable offsets
  320.                            ** used by the mark phase of the garbage
  321.                            ** collector.
  322.                            *)
  323.  
  324.   traced   : SYS.ADDRESS;  (* The root of the list of traceable memory
  325.                            ** blocks. This list is scanned by the sweep
  326.                            ** phase of the garbage collector. This list
  327.                            ** can contain any type of block.
  328.                            *)
  329.  
  330.   untraced : SYS.ADDRESS;  (* The root of the list of untraced memory
  331.                            ** blocks. These blocks are ignored by the
  332.                            ** garbage collector. There should only be
  333.                            ** SysBlks in this list.
  334.                            *)
  335.  
  336.  
  337. (*-----------------------------------------------------------------------**
  338. ** This variable holds a pointer to the program's Process structure.     **
  339. **-----------------------------------------------------------------------*)
  340.  
  341. VAR
  342.  
  343.   process : ProcessPtr;
  344.  
  345.  
  346. (*-----------------------------------------------------------------------**
  347. ** These types are used to implement the automatic cleanup system.       **
  348. **-----------------------------------------------------------------------*)
  349.  
  350. TYPE
  351.  
  352.   CleanupProc * = PROCEDURE (VAR rc : LONGINT);
  353.  
  354.   CleanupPtr = POINTER [1] TO CleanupRec;
  355.   CleanupRec = RECORD [1]
  356.     link : CleanupPtr;
  357.     proc : CleanupProc;
  358.   END; (* CleanupRec *)
  359.  
  360.  
  361. (*-----------------------------------------------------------------------**
  362. ** This variable is used to hold the list of installed cleanup           **
  363. ** procedures.                                                           **
  364. **-----------------------------------------------------------------------*)
  365.  
  366. VAR
  367.  
  368.   cleanupList : CleanupPtr;
  369.  
  370.  
  371. (*-----------------------------------------------------------------------**
  372. ** Variables used to install and remove a trap handler.                  **
  373. **-----------------------------------------------------------------------*)
  374.  
  375. VAR
  376.  
  377.   userTraps   : SET;        (* The user traps allocated for the program. *)
  378.   handlerInstalled : BOOLEAN; (* Is the handler installed? *)
  379.   oldTrapCode : PROC;        (* The initial trap handler. *)
  380.   oldTrapData : SYS.ADDRESS; (* The initial trap data. *)
  381.  
  382.  
  383. (*-----------------------------------------------------------------------**
  384. ** Variables used to report the position of errors.                      **
  385. **-----------------------------------------------------------------------*)
  386.  
  387. VAR
  388.  
  389.   errModule -: ARRAY 32 OF CHAR;
  390.   errLine   -: INTEGER;
  391.   errCol    -: INTEGER;
  392.  
  393.  
  394. (*-----------------------------------------------------------------------**
  395. ** Exec library functions used by this module. Note that the parameter   **
  396. ** and return types do not exactly match the declarations in module      **
  397. ** Exec.                                                                 **
  398. **-----------------------------------------------------------------------*)
  399.  
  400.  
  401. PROCEDURE Forbid [SysBase,-132] ();
  402. PROCEDURE AllocMem [SysBase,-198]
  403.   ( byteSize     [0] : LONGINT;
  404.     requirements [1] : SET )
  405.   : SYS.ADDRESS;
  406. PROCEDURE FreeMem [SysBase,-210]
  407.   ( memoryBlock [9] : SYS.ADDRESS;
  408.     byteSize    [0] : LONGINT );
  409. PROCEDURE FindTask [SysBase,-294]
  410.   ( name [9] : STRPTR )
  411.   : ProcessPtr;
  412. PROCEDURE AllocTrap [SysBase,-342]
  413.   ( trapNum [0] : LONGINT )
  414.   : SHORTINT;
  415. PROCEDURE FreeTrap [SysBase,-348]
  416.   ( trapNum [0] : LONGINT );
  417. PROCEDURE GetMsg [SysBase,-372]
  418.   ( VAR port [8] : MsgPort )
  419.   : SYS.ADDRESS;
  420. PROCEDURE ReplyMsg [SysBase,-378]
  421.   ( message [9] : SYS.ADDRESS );
  422. PROCEDURE WaitPort [SysBase,-384]
  423.   ( VAR port [8] : MsgPort );
  424. PROCEDURE OpenLibrary [SysBase,-552]
  425.   ( libName [9] : ARRAY OF CHAR;
  426.     version [0] : LONGINT )
  427.   : LibraryPtr;
  428. PROCEDURE CopyMem [SysBase,-624]
  429.   ( source [8] : LONGINT;
  430.     dest   [9] : LONGINT;
  431.     size   [0] : LONGINT );
  432.  
  433.  
  434. (*-----------------------------------------------------------------------*)
  435.  
  436.  
  437. (* FreeMemBlock() returns a block of memory to the system. It determines
  438. ** the type of block by inspecting the type bits in the size/tag
  439. ** longword.
  440. *)
  441.  
  442. PROCEDURE FreeMemBlock ( mem : MemBlockPtr );
  443.  
  444.   VAR size : LONGINT; sizeTag : SET;
  445.  
  446. BEGIN (* FreeMemBlock *)
  447.   sizeTag := mem.sizeTag;
  448.   (* Clearing bit 31 in sizeTag allows this procedure to work even if
  449.   ** the program halts during the mark phase of the garbage collector.
  450.   *)
  451.   EXCL (sizeTag, 31);
  452.   IF 0 IN sizeTag THEN (* SysBlk *)
  453.     size := SYS.VAL (LONGINT, sizeTag) - 1;
  454.     INC (size, SIZE (SysBlk))
  455.   ELSIF 1 IN sizeTag THEN (* ArrayBlk *)
  456.     DEC (SYS.VAL (LONGINT, mem), 12);
  457.     SYS.GET (SYS.VAL (LONGINT, mem) + 8, size);
  458.     INC (size, SIZE (ArrayBlk))
  459.   ELSE (* RecordBlk *)
  460.     SYS.GET (SYS.VAL (LONGINT, sizeTag), size);
  461.     INC (size, SIZE (RecordBlk))
  462.   END;
  463.   FreeMem (mem, size);
  464. END FreeMemBlock;
  465.  
  466.  
  467. (* DoCleanup is responsible for any cleanup required before exiting the
  468. ** program. It is called by Halt() and TrapHandler().
  469. *)
  470.  
  471. PROCEDURE* DoCleanup
  472.   ( rc : LONGINT; module : STRPTR; pos : LONGINT );
  473.  
  474.   VAR mem, next : MemBlockPtr; cleanupPtr : CleanupPtr; t : LONGINT;
  475.  
  476. BEGIN (* DoCleanup *)
  477.   IF module # NIL THEN
  478.     COPY (module^, errModule);
  479.     errLine := SHORT (pos DIV 10000H); errCol := SHORT (pos MOD 10000H)
  480.   ELSE
  481.     errModule := ""; errLine := 0; errCol := 0
  482.   END;
  483.  
  484.   (* Execute any installed cleanup procedures. *)
  485.  
  486.   cleanupPtr := cleanupList;
  487.   cleanupList := NIL; (* This avoids loops if an error occurs in a
  488.                       ** cleanup procedure.
  489.                       *)
  490.   WHILE cleanupPtr # NIL DO
  491.     cleanupPtr.proc (rc);
  492.     cleanupPtr := cleanupPtr.link
  493.   END;
  494.  
  495.   (* Free all memory allocated by the program. This must be done *after*
  496.   ** any cleanup procedures, in case they allocate memory.
  497.   *)
  498.  
  499.   mem := traced; traced := NIL;
  500.   WHILE mem # NIL DO
  501.     next := mem.link;
  502.     FreeMemBlock (mem);
  503.     mem := next;
  504.   END;
  505.  
  506.   mem := untraced; untraced := NIL;
  507.   WHILE mem # NIL DO
  508.     next := mem.link;
  509.     FreeMemBlock (mem);
  510.     mem := next;
  511.   END;
  512.  
  513.   (* This is the *last* code executed by the program. *)
  514.  
  515.   IF fromWorkbench THEN
  516.     Forbid;              (* Stops AmigaDOS from unloading us *)
  517.     ReplyMsg (WBenchMsg) (* Tells Workbench to do it instead *)
  518.   END;
  519.  
  520.   SYS.SETREG (0, rc)             (* Sets return code for Dos *)
  521. END DoCleanup;
  522.  
  523.  
  524. (*-----------------------------------------------------------------------**
  525. ** The following procedures are known to the compiler. DO NOT RENAME OR  **
  526. ** REMOVE THEM. They should not be exported, but must be marked as       **
  527. ** assignable or the LongVars+ pragma switched on so that they can       **
  528. ** access global variables.                                              **
  529. **-----------------------------------------------------------------------*)
  530.  
  531.  
  532. (* Linker Symbol: "Kernel_Halt"
  533. **
  534. ** This procedure is called as the result of a HALT or ASSERT statement,
  535. ** and also when the program exits normally by reaching the END in the
  536. ** main body of the main module. The return code is passed in register D0.
  537. **
  538. ** Halt restores the stack pointer to the value held in the initialSP
  539. ** variable. As a result, it must not declare any local variables.
  540. **
  541. ** The LongVars pragma is used to stop the compiler loading the module's
  542. ** global variable base into A4. As a consequence, DoCleanup() must be
  543. ** declared as PROCEDURE* (ie - assignable) so that it can access global
  544. ** variables.
  545. *)
  546.  
  547. <*$ < LongVars+ *>
  548. PROCEDURE Halt;
  549.  
  550. BEGIN (* Halt *)
  551.   (* Restore initial stack pointer. *)
  552.   SYS.SETREG (15, initialSP);
  553.   (* Do any remaining cleanup. *)
  554.   DoCleanup (SYS.REG (0), SYS.VAL (STRPTR, SYS.REG (8)), SYS.REG (1));
  555. END Halt;
  556. <*$ > *>
  557.  
  558.  
  559. (* Linker symbol : Kernel_NewRecord
  560. **
  561. ** NewRecord() is called by the compiler to implement a NEW call, when
  562. ** the parameter is a POINTER TO RECORD type.
  563. **
  564. ** The parameter is the address of the type descriptor of the RECORD
  565. ** type.
  566. *)
  567.  
  568. PROCEDURE* NewRecord ( tag : SYS.TYPETAG ) : SYS.PTR;
  569.  
  570.   VAR
  571.     memBlock : RecordBlkPtr; (* Points to the allocated memory. *)
  572.     size : LONGINT;
  573.  
  574. <*$ReturnChk-*>
  575. BEGIN (* NewRecord *)
  576.   memBlock := NIL;
  577.   SYS.GET (SYS.VAL (LONGINT, tag), size);
  578.   IF size > 0 THEN
  579.     memBlock := AllocMem (size + SIZE (RecordBlk), {memClear});
  580.     IF memBlock # NIL THEN
  581.       memBlock.link := traced; traced := memBlock;
  582.       memBlock.tag := tag;
  583.       <* IF DEBUG1 THEN *>
  584.       memBlock.id := RecordBlkId;
  585.       <* END *>
  586.       INC (SYS.VAL (LONGINT, memBlock), SIZE (RecordBlk))
  587.     END
  588.   END;
  589.   RETURN SYS.VAL (SYS.PTR, memBlock)
  590. END NewRecord;
  591.  
  592.  
  593. (* Linker symbol : Kernel_NewArray
  594. **
  595. ** NewArray() is called by the compiler to implement a NEW call, when the
  596. ** parameter is a POINTER TO ARRAY OF RECORD type.
  597. **
  598. ** The tag parameter is the address of the type descriptor of the RECORD
  599. ** type. The size parameter is the total size of the array, calculated
  600. ** inline by the compiler.
  601. *)
  602.  
  603. PROCEDURE* NewArray ( tag : SYS.TYPETAG; size : LONGINT ) : SYS.PTR;
  604.  
  605.   VAR memBlock : ArrayBlkPtr; (* Points to the allocated memory. *)
  606.  
  607. <*$ReturnChk-*>
  608. BEGIN (* NewArray *)
  609.   memBlock := NIL;
  610.   IF size > 0 THEN
  611.     memBlock := AllocMem (size + SIZE (ArrayBlk), {memClear});
  612.     IF memBlock # NIL THEN
  613.       memBlock.link := traced; traced := SYS.ADR (memBlock.link);
  614.       memBlock.tag := SYS.VAL (SYS.TYPETAG, SYS.VAL (LONGINT, tag) + 2);
  615.       SYS.GET (SYS.VAL (LONGINT, tag), memBlock.elemSize);
  616.       memBlock.size := size;
  617.       <* IF DEBUG1 THEN *>
  618.       memBlock.id := ArrayBlkId;
  619.       <* END *>
  620.       INC (SYS.VAL (LONGINT, memBlock), SIZE (ArrayBlk))
  621.     END
  622.   END;
  623.   RETURN SYS.VAL (SYS.PTR, memBlock)
  624. END NewArray;
  625.  
  626.  
  627. (* Linker symbol: Kernel_NewSysBlk
  628. **
  629. ** NewSysBlk() is called by the compiler to implement a NEW or SYSTEM.NEW
  630. ** call, when an untyped memory block is required.
  631. **
  632. ** The size parameter is the number of bytes required, and the isTraced
  633. ** parameter determines which memory list the chunk is to be linked to.
  634. *)
  635.  
  636. PROCEDURE* NewSysBlk ( size : LONGINT; isTraced : BOOLEAN )
  637.   : SYS.ADDRESS;
  638.  
  639.   VAR memBlock : SysBlkPtr; (* Points to the allocated memory. *)
  640.  
  641. <*$ReturnChk-*>
  642. BEGIN (* NewSysBlk *)
  643.   memBlock := NIL;
  644.   IF size > 0 THEN
  645.     (* Round size up to next multiple of 4 -- VERY IMPORTANT *)
  646.     size := SYS.AND (size + 3, 0FFFFFFFCH);
  647.     memBlock := AllocMem (size + SIZE (SysBlk), {memClear});
  648.     IF memBlock # NIL THEN
  649.       IF isTraced THEN memBlock.link := traced; traced := memBlock
  650.       ELSE memBlock.link := untraced; untraced := memBlock;
  651.       END;
  652.       memBlock.size := size + 1;
  653.       <* IF DEBUG1 THEN *>
  654.       memBlock.id := SysBlkId;
  655.       <* END *>
  656.       INC (SYS.VAL (LONGINT, memBlock), SIZE (SysBlk))
  657.     END
  658.   END;
  659.   RETURN memBlock
  660. END NewSysBlk;
  661.  
  662.  
  663. (* Linker symbol: Kernel_Dispose
  664. **
  665. ** Dispose() is called by the compiler to implement a SYSTEM.DISPOSE
  666. ** call.
  667. **
  668. ** The parameter is the address of the variable to be freed. The untraced
  669. ** and traced memory lists are searched first to determine if the
  670. ** variable points to a memory block that has been allocated by the
  671. ** program. If not, the program is HALTed with a return code of 21.
  672. *)
  673.  
  674. PROCEDURE Dispose* ( VAR adr : SYS.ADDRESS );
  675.  
  676.   VAR mem, last, next : MemBlockPtr; size : LONGINT;
  677.  
  678. BEGIN (* Dispose *)
  679.   mem := adr;
  680.   IF mem # NIL THEN
  681.     DEC (SYS.VAL (LONGINT, mem), SIZE (MemBlock));
  682.     last := SYS.ADR (untraced); next := untraced;
  683.     WHILE (next # NIL) & (next # mem) DO
  684.       last := next; next := next.link
  685.     END;
  686.     IF next = NIL THEN
  687.       last := SYS.ADR (traced); next := traced;
  688.       WHILE (next # NIL) & (next # mem) DO
  689.         last := next; next := next.link
  690.       END;
  691.       IF next = NIL THEN HALT (21) END
  692.     END;
  693.     last.link := next.link;
  694.     FreeMemBlock (mem);
  695.     adr := NIL
  696.   END
  697. END Dispose;
  698.  
  699.  
  700. (* Linker symbol : Kernel_InitGC
  701. **
  702. ** InitGC() links a module's GC offset block into a global list, which is
  703. ** traversed by the mark phase of the garbage collector. It is called
  704. ** invisibly in the module's initialisation code if it has any global
  705. ** traced pointers.
  706. *)
  707.  
  708. <*$ < LongVars+ *>
  709. PROCEDURE* InitGC ( offsets : GCOffsetPtr );
  710. BEGIN (* InitGC *)
  711.   offsets.link := gcBase; gcBase := offsets
  712. END InitGC;
  713. <*$ > *>
  714.  
  715.  
  716. (* Linker symbol : Kernel_Move
  717. **
  718. ** This procedure implements the SYSTEM.MOVE procedure.
  719. *)
  720.  
  721. <*$ < LongVars+ NilChk- *>
  722. PROCEDURE Move ( src, dst, len : LONGINT );
  723.  
  724.   VAR byte : SYS.BYTE;
  725.  
  726. BEGIN (* Move *)
  727.   IF (src # dst) & (len > 0) THEN
  728.     IF (dst > src) & (dst < (src + len)) THEN
  729.       (* The blocks overlap, copy bytes from the *top* down *)
  730.       INC (src, len); INC (dst, len);
  731.       REPEAT
  732.         DEC (src); DEC (dst);
  733.         SYS.GET (src, byte); SYS.PUT (dst, byte);
  734.         DEC (len)
  735.       UNTIL len = 0
  736.     ELSIF (src > dst) & (src < (dst + len)) THEN
  737.       (* The blocks overlap, copy bytes from the *bottom* up *)
  738.       REPEAT
  739.         SYS.GET (src, byte); SYS.PUT (dst, byte);
  740.         INC (src); INC (dst);
  741.         DEC (len)
  742.       UNTIL len = 0
  743.     ELSE
  744.       (* Non-overlapping blocks, let CopyMem() do it. *)
  745.       CopyMem (src, dst, len)
  746.     END;
  747.   END
  748. END Move;
  749. <*$ > *>
  750.  
  751.  
  752. (* Linker symbol : Kernel_StackChk
  753. **
  754. ** This procedure implements stack checking for the compiler. The size of
  755. ** the additional stack required is passed in register D0.
  756. *)
  757.  
  758. <*$ < LongVars+ EntryExitCode- *> (* Stack pragma state *)
  759. PROCEDURE StackChk;
  760. BEGIN (* StackChk *)
  761.   SYS.INLINE (02F08H);    (*    MOVE.L A0, -(A7)    *)
  762.   SYS.SETREG (8,SysBase); (*    MOVE.L SysBase,A0   *)
  763.   SYS.INLINE (
  764.     02068H, 00114H,       (*    MOVE.L 0114(A0), A0 *)
  765.     02068H, 0003AH,       (*    MOVE.L 003A(A0), A0 *)
  766.     -2E40H,               (*    ADD.L  D0, A0       *)
  767.     041E8H, 1500,         (*    LEA    1500(A0), A0 *)
  768.     -4E31H,               (*    CMPA.L A7,  A0      *)
  769.     0630AH,               (*    BLS    1$           *)
  770.     04E45H,               (*    TRAP   #5           *)
  771.     0,0,                  (*    DC.L   moduleName   *)
  772.     0,                    (*    DC.W   line         *)
  773.     0,                    (*    DC.W   col          *)
  774.     0205FH,               (* 1$ MOVE.L (A7)+, A0    *)
  775.     04E75H                (*    RTS                 *)
  776.   ); (* INLINE *)
  777. END StackChk;
  778. <*$ > *> (* Unstack pragmas *)
  779.  
  780.  
  781. (*-----------------------------------------------------------------------**
  782. ** The following procedures implement REAL arithmetic. They are known to **
  783. ** the compiler and MUST NOT BE REMOVED OR RENAMED. They receive their   **
  784. ** parameters in registers. They should not be exported, or marked as    **
  785. ** assignable.                                                           **
  786. **                                                                       **
  787. ** The REAL math routines access the mathBase variable using long        **
  788. ** addressing for efficiency. The compiler places the arguments in the   **
  789. ** appropriate registers before calling them. These are really just      **
  790. ** stubs that are used to remove the need for the compiler to know       **
  791. ** about the mathBase variable. They use JMP instead of JSR for the call **
  792. ** to save one RTS: the library function will return direct to the       **
  793. ** calling code instead of here.                                         **
  794. **-----------------------------------------------------------------------*)
  795.  
  796. <*$ < LongVars+ *> (* Stack pragma state *)
  797.  
  798. PROCEDURE SPFix;
  799. (* It appears to be a "feature" of the Commodore math libraries that the
  800. ** *Fix functions behave differently when used on machines with and without
  801. ** hardware FPUs. Sometimes it truncates, sometimes it rounds. Since *Fix
  802. ** cannot be relied on to truncate the result, we must do it ourselves.
  803. *)
  804.  
  805. <*$EntryExitCode-*>
  806. BEGIN (* SPFix *)
  807.   SYS.INLINE (02F00H);                      (*    MOVE.L  D0,-(A7)       *)
  808.   SYS.SETREG (14, mathBase);                (*    MOVEA.L mathBase,A6    *)
  809.   SYS.SETREG (1, SYS.REG (0));              (*    MOVE.L  D0,D1          *)
  810.   SYS.INLINE (4EAEH,-48);                   (*    JSR     LVOSPTst(A6)   *)
  811.   SYS.INLINE (06C08H);                      (*    BGE     1$             *)
  812.   SYS.INLINE (0201FH);                      (*    MOVE.L  (A7)+,D0       *)
  813.   SYS.INLINE (4EAEH,-96);                   (*    JSR     LVOSPCeil(A6)  *)
  814.   SYS.INLINE (06006H);                      (*    BRA.S   2$             *)
  815.   SYS.INLINE (0201FH);                      (* 1$ MOVE.L  (A7)+,D0       *)
  816.   SYS.INLINE (4EAEH,-90);                   (*    JSR     LVOSPFloor(A6) *)
  817.   SYS.INLINE (4EEEH,-30);                   (* 2$ JMP     LVOSPFix(A6)   *)
  818. END SPFix;
  819.  
  820. PROCEDURE SPFlt;
  821. <*$EntryExitCode-*>
  822. BEGIN (* SPFlt *)
  823.   SYS.SETREG (14, mathBase);                     (* MOVEA.L mathBase,A6  *)
  824.   SYS.INLINE (4EEEH,-36);                        (* JMP     LVOSPFlt(A6) *)
  825. END SPFlt;
  826.  
  827. PROCEDURE SPCmp;
  828. <*$EntryExitCode-*>
  829. BEGIN (* SPCmp *)
  830.   SYS.SETREG (14, mathBase);                     (* MOVEA.L mathBase,A6  *)
  831.   SYS.INLINE (4EEEH,-42);                        (* JMP     LVOSPCmp(A6) *)
  832. END SPCmp;
  833.  
  834. (* REAL is now IEEE single-precision, so this doesn't happen.
  835. PROCEDURE SPTst;
  836. (* MathFFP.SPTst takes its parameter in D1 instead of D0 as you would
  837. ** expect. To avoid complicating matters, the compiler passes the parameter
  838. ** in D0 anyway, and the stub copies it to D1.
  839. *)
  840.  
  841. <*$EntryExitCode-*>
  842. BEGIN (* SPTst *)
  843.   SYS.SETREG (1, SYS.REG (0));                   (* MOVE.L  D0,D1        *)
  844.   SYS.SETREG (14, mathBase);                     (* MOVEA.L mathBase,A6  *)
  845.   SYS.INLINE (4EEEH,-48);                        (* JMP     LVOSPTst(A6) *)
  846. END SPTst;
  847. *)
  848.  
  849. PROCEDURE SPTst;
  850.  
  851. <*$EntryExitCode-*>
  852. BEGIN (* SPTst *)
  853.   SYS.SETREG (14, mathBase);                     (* MOVEA.L mathBase,A6  *)
  854.   SYS.INLINE (4EEEH,-48);                        (* JMP     LVOSPTst(A6) *)
  855. END SPTst;
  856.  
  857. PROCEDURE SPAbs;
  858. <*$EntryExitCode-*>
  859. BEGIN (* SPAbs *)
  860.   SYS.SETREG (14, mathBase);                     (* MOVEA.L mathBase,A6  *)
  861.   SYS.INLINE (4EEEH,-54);                        (* JMP     LVOSPAbs(A6) *)
  862. END SPAbs;
  863.  
  864. PROCEDURE SPNeg;
  865. <*$EntryExitCode-*>
  866. BEGIN (* SPNeg *)
  867.   SYS.SETREG (14, mathBase);                     (* MOVEA.L mathBase,A6  *)
  868.   SYS.INLINE (4EEEH,-60);                        (* JMP     LVOSPNeg(A6) *)
  869. END SPNeg;
  870.  
  871. PROCEDURE SPAdd;
  872. <*$EntryExitCode-*>
  873. BEGIN (* SPAdd *)
  874.   SYS.SETREG (14, mathBase);                     (* MOVEA.L mathBase,A6  *)
  875.   SYS.INLINE (4EEEH,-66);                        (* JMP     LVOSPAdd(A6) *)
  876. END SPAdd;
  877.  
  878. PROCEDURE SPSub;
  879. <*$EntryExitCode-*>
  880. BEGIN (* SPSub *)
  881.   SYS.SETREG (14, mathBase);                     (* MOVEA.L mathBase,A6  *)
  882.   SYS.INLINE (4EEEH,-72);                        (* JMP     LVOSPSub(A6) *)
  883. END SPSub;
  884.  
  885. PROCEDURE SPMul;
  886. <*$EntryExitCode-*>
  887. BEGIN (* SPMul *)
  888.   SYS.SETREG (14, mathBase);                     (* MOVEA.L mathBase,A6  *)
  889.   SYS.INLINE (4EEEH,-78);                        (* JMP     LVOSPMul(A6) *)
  890. END SPMul;
  891.  
  892. PROCEDURE SPDiv;
  893. <*$EntryExitCode-*>
  894. BEGIN (* SPDiv *)
  895.   SYS.SETREG (14, mathBase);                     (* MOVEA.L mathBase,A6  *)
  896.   SYS.INLINE (4EEEH,-84);                        (* JMP     LVOSPDiv(A6) *)
  897. END SPDiv;
  898.  
  899. <*$ > *> (* Unstack pragmas *)
  900.  
  901.  
  902. (*-----------------------------------------------------------------------**
  903. ** Multiplication and division of 32-bit integers is done in software,   **
  904. ** in the abscence of appropriate instructions for the MC68000 CPU. The  **
  905. ** procedures that perform this task are too large to be coded inline,   **
  906. ** so they are assembled seperately to the object file "LMath.o",        **
  907. ** which is listed as an external library in the module header. See      **
  908. ** "LMath.asm" for the source code. The external declarations for these  **
  909. ** procedures are given below, purely for reference.                     **
  910. **-----------------------------------------------------------------------*)
  911.  
  912.  
  913. PROCEDURE [4] Mul32 ["Kernel_Mul32"] (l1 [0], l2 [1] : LONGINT) : LONGINT;
  914.  
  915. PROCEDURE [4] Div32 ["Kernel_Div32"] (l1 [0], l2 [1] : LONGINT) : LONGINT;
  916.  
  917.  
  918. (*-----------------------------------------------------------------------**
  919. ** Procedures declared after this point are not known to the compiler.   **
  920. **-----------------------------------------------------------------------*)
  921.  
  922.  
  923. (* TrapHandler() is installed in the tcTrapCode field of the process
  924. ** structure by InstallTrapHandler(). Its job is to deal with any processor
  925. ** traps generated by the program. It is executed in supervisor mode, so it
  926. ** must do its job as quickly as possible, then get out of supervisor mode
  927. ** using an RTE instruction.
  928. **
  929. ** The stack looks like this when TrapHandler() is called:
  930. **
  931. **   6(SP) - (LONG) PC when trap occurred
  932. **   4(SP) - (WORD) SR when trap occurred
  933. **   0(SP) - (LONG) Trap #
  934. **
  935. ** This procedure should only concern itself with traps that are known
  936. ** to be generated by Oberon-A programs. These are traps 2..8, 10..11 and
  937. ** 32..38 (user traps 0..6). Anything else should be propagated to the
  938. ** trap handler stored in oldTrapCode.
  939. *)
  940.  
  941. PROCEDURE* TrapHandler;
  942.  
  943. <*$ < EntryExitCode- LongVars+*>
  944. BEGIN (* TrapHandler *)
  945.   (* Check if the trap is ours to handle *)
  946.   SYS.INLINE (00C97H,0,9);        (*    CMP.L  #9,(A7)         *)
  947.   SYS.INLINE (06772H);            (*    BEQ.S  1$              *)
  948.   SYS.INLINE (00C97H,0,2);        (*    CMP.L  #2,(A7)         *)
  949.   SYS.INLINE (0656AH);            (*    BLO.S  1$              *)
  950.   SYS.INLINE (00C97H,0,11);       (*    CMP.L  #11,(A7)        *)
  951.   SYS.INLINE (06310H);            (*    BLS.S  2$              *)
  952.   SYS.INLINE (00C97H,0,32);       (*    CMP.L  #32,(A7)        *)
  953.   SYS.INLINE (0655AH);            (*    BLO.S  1$              *)
  954.   SYS.INLINE (00C97H,0,38);       (*    CMP.L  #38,(A7)        *)
  955.   SYS.INLINE (06252H);            (*    BHI.S  1$              *)
  956.  
  957.   (* It's ours *)
  958.   (* Pop the trap number off the stack. *)
  959.   SYS.INLINE (201FH);             (* 2$ MOVE.L (A7)+,D0        *)
  960.  
  961.   (* IF trapno IN {CHK,TRAPV,32..38}) THEN *)
  962.   SYS.INLINE (00C80H,0,6);        (*    CMP.L  #6,D0           *)
  963.   SYS.INLINE (06724H);            (*    BEQ.S  4$              *)
  964.   SYS.INLINE (00C80H,0,7);        (*    CMP.L  #7,D0           *)
  965.   SYS.INLINE (0671CH);            (*    BEQ.S  4$              *)
  966.   SYS.INLINE (00C80H,0,32);       (*    CMP.L  #32,D0          *)
  967.   SYS.INLINE (06522H);            (*    BLO.S  5$              *)
  968.   SYS.INLINE (00C80H,0,38);       (*    CMP.L  #38,D0          *)
  969.   SYS.INLINE (0621AH);            (*    BHI.S  5$              *)
  970.  
  971.   (* Get the module name and source code position. These are
  972.   ** embedded in the object code by the compiler, immediately
  973.   ** after the trap instruction. There is an additional short
  974.   ** branch directly after a CHK or TRAPV instruction.
  975.   *)
  976.  
  977.   SYS.INLINE (0226FH,2);          (*    MOVE.L 2(A7),A1        *)
  978.   SYS.INLINE (02051H);            (*    MOVE.L (A1),A0         *)
  979.   SYS.INLINE (02229H,4);          (*    MOVE.L 4(A1),D1        *)
  980.   SYS.INLINE (6012H);             (*    BRA.S  $6              *)
  981.  
  982.   SYS.INLINE (0226FH,2);          (* 4$ MOVE.L 2(A7),A1        *)
  983.   SYS.INLINE (02069H,2);          (*    MOVE.L 2(A1),A0        *)
  984.   SYS.INLINE (02229H,6);          (*    MOVE.L 6(A1),D1        *)
  985.   SYS.INLINE (6004H);             (*    BRA.S  $6              *)
  986.  
  987.   (* ELSE *)
  988.   SYS.INLINE (-6E38H);            (* 5$ SUBA.L A0,A0           *)
  989.   SYS.INLINE (07200H);            (*    MOVEQ  #0,D1           *)
  990.  
  991.   (* Add 100 to the trap number *)
  992.   SYS.INLINE (0680H,0,100);       (* 6$ ADDI.L #100,D0         *)
  993.  
  994.   (* Replace the old PC with the address of Halt() *)
  995.   SYS.SETREG (9, Halt);           (*    MOVE.L #Kernel_Halt,A1 *)
  996.   SYS.INLINE (2F49H,2);           (*    MOVE.L A1,2(A7)        *)
  997.  
  998.   (* Call Halt() *)
  999.   SYS.INLINE (4E73H);             (*    RTE                    *)
  1000.  
  1001.   (* Never seen it before in my life, y'honour *)
  1002.   SYS.SETREG (0, oldTrapCode);    (* 1$ MOVE.L oldTrapCode,D0  *)
  1003.   SYS.INLINE (06704H);            (*    BEQ.S  3$              *)
  1004.   SYS.INLINE (02F00H);            (*    MOVE.L D0,-(A7)        *)
  1005.   SYS.INLINE (04E75H);            (*    RTS                    *)
  1006.   SYS.INLINE (0588FH);            (* 3$ ADDQ.L #4,A7           *)
  1007.   SYS.INLINE (04E73H);            (*    RTE                    *)
  1008. END TrapHandler;
  1009. <*$ > *>
  1010.  
  1011. (* SetCleanup() installs a procedure that will be executed automatically
  1012. ** when the program exits.
  1013. *)
  1014.  
  1015. PROCEDURE SetCleanup * ( proc : CleanupProc );
  1016.  
  1017.   VAR newCleanup : CleanupPtr;
  1018.  
  1019. BEGIN (* SetCleanup *)
  1020.   newCleanup := NewSysBlk (SIZE (CleanupRec), FALSE);
  1021.   IF newCleanup = NIL THEN HALT (22) END;
  1022.   newCleanup.link := cleanupList; cleanupList := newCleanup;
  1023.   newCleanup.proc := proc
  1024. END SetCleanup;
  1025.  
  1026.  
  1027. (* Size() returns the size in bytes of the record type whose type tag
  1028. ** is passed as a parameter. The type tag is obtained by a call to
  1029. ** SYSTEM.TAG.
  1030. *)
  1031.  
  1032. <*$ < LongVars+ *> (* No global variables used *)
  1033. PROCEDURE Size * ( type : SYS.TYPETAG ) : LONGINT;
  1034.  
  1035.   VAR size : LONGINT;
  1036.  
  1037. BEGIN (* Size *)
  1038.   ASSERT (type # NIL, 97);
  1039.   SYS.GET (SYS.VAL (LONGINT, type), size);
  1040.   RETURN size
  1041. END Size;
  1042. <*$ > *>
  1043.  
  1044.  
  1045. (* Name() copies the name of the type whose type tag is passed as a
  1046. ** parameter into a string variable. The type tag is obtained by a call to
  1047. ** SYSTEM.TAG.
  1048. **
  1049. ** This procedure relies on the type tag being a pointer to a valid type
  1050. ** descriptor, which has the following structure:
  1051. **
  1052. **   TypeDesc = RECORD
  1053. **     size        : LONGINT;
  1054. **     tagTable    : ARRAY 8 OF SYSTEM.TYPETAG;
  1055. **     offsetTable : ARRAY numOffsets OF LONGINT;
  1056. **     name        : ARRAY nameLen+1 OF CHAR;
  1057. **   END;
  1058. **
  1059. ** The offsetTable array is terminated by a negative offset, which this
  1060. ** procedure uses to find the start of the name field.
  1061. *)
  1062.  
  1063. <*$ < LongVars+ *> (* No global variables used *)
  1064. PROCEDURE Name * ( type : SYS.TYPETAG; VAR buf : ARRAY OF CHAR );
  1065.  
  1066.   VAR name : STRPTR; offset : LONGINT;
  1067.  
  1068. BEGIN (* Name *)
  1069.   ASSERT (type # NIL, 97);
  1070.   (* Point name at the start of the offsetTable field. *)
  1071.   name := SYS.VAL (STRPTR, SYS.VAL (LONGINT, type) + 36);
  1072.   (* Scan offsetTable until a negative offset is found *)
  1073.   REPEAT
  1074.     SYS.GET (name, offset);
  1075.     INC (SYS.VAL (LONGINT, name), 4);
  1076.   UNTIL offset < 0;
  1077.   (* name now points to the name field. *)
  1078.   COPY (name^, buf)
  1079. END Name;
  1080. <*$ > *>
  1081.  
  1082.  
  1083. (* New() allocates a new record from the type tag passed as a parameter.
  1084. ** The type tag is obtained by a call to SYSTEM.TAG.
  1085. *)
  1086.  
  1087. PROCEDURE New * ( VAR v : SYS.PTR; type : SYS.TYPETAG );
  1088. BEGIN (* New *)
  1089.   ASSERT (type # NIL, 97);
  1090.   v := NewRecord (type)
  1091. END New;
  1092.  
  1093.  
  1094. (* Allocate() allocates a block of memory with an arbitrary size and with
  1095. ** the given memory requirements. This block will be untraced, and so can
  1096. ** only be referenced through an untagged pointer (system flag # [0]).
  1097. *)
  1098.  
  1099. PROCEDURE Allocate * ( VAR v : SYS.ADDRESS; size : LONGINT; reqs : SET );
  1100.  
  1101.   VAR memBlock : SysBlkPtr; (* Points to the allocated memory. *)
  1102.  
  1103. BEGIN (* Allocate *)
  1104.   IF size > 0 THEN
  1105.     (* Round size up to next multiple of 4 -- VERY IMPORTANT *)
  1106.     size := SYS.AND (size + 3, 0FFFFFFFCH);
  1107.     memBlock := AllocMem (size + SIZE (SysBlk), reqs);
  1108.     IF memBlock # NIL THEN
  1109.       memBlock.link := untraced; untraced := memBlock;
  1110.       memBlock.size := size + 1;
  1111.       <* IF DEBUG1 THEN *>
  1112.       memBlock.id := SysBlkId;
  1113.       <* END *>
  1114.       INC (SYS.VAL (LONGINT, memBlock), SIZE (SysBlk))
  1115.     END;
  1116.     v := memBlock
  1117.   ELSE
  1118.     v := NIL
  1119.   END
  1120. END Allocate;
  1121.  
  1122.  
  1123. (*-----------------------------------------------------------------------**
  1124. ** The following procedures implement the garbage collector, which is a  **
  1125. ** mark-and-sweep collector based on the algorithm described in the      **
  1126. ** Oberon Technical Notes.                                               **
  1127. **-----------------------------------------------------------------------*)
  1128.  
  1129.  
  1130. (* Mark() is the heart of the garbage collector. It is written in assembly
  1131. ** language for speed, but is too large to be implemented as inline code.
  1132. ** Instead, it is assembled seperetely to the object file "Mark.o",
  1133. ** which is listed as an external library in the module header. See
  1134. ** "Mark.asm" for the source code.
  1135. *)
  1136.  
  1137. PROCEDURE [4] Mark ["Kernel_Mark"] ( q [8] : SYS.LONGWORD );
  1138.  
  1139.  
  1140. (* Sweep() walks the list of traced memory blocks, unmarking any marked
  1141. ** blocks and freeing all unmarked blocks.
  1142. *)
  1143.  
  1144. PROCEDURE Sweep;
  1145.  
  1146.   VAR mem, prev, next : MemBlockPtr;
  1147.  
  1148. BEGIN (* Sweep *)
  1149.   prev := SYS.ADR (traced); next := traced;
  1150.   WHILE next # NIL DO
  1151.     IF 31 IN next.sizeTag THEN
  1152.       (* next is marked, unmark it and move on *)
  1153.       EXCL (next.sizeTag, 31);
  1154.       prev := next;
  1155.       next := next.link
  1156.     ELSE
  1157.       (* unlink the block and free it *)
  1158.       mem := next;
  1159.       next := next.link;
  1160.       prev.link := next;
  1161.       FreeMemBlock (mem)
  1162.     END
  1163.   END
  1164. END Sweep;
  1165.  
  1166.  
  1167. (*
  1168. **
  1169. *)
  1170.  
  1171. PROCEDURE GC*;
  1172. BEGIN (* GC *)
  1173.   SYS.SETREG (14, gcBase);
  1174.   SYS.INLINE (
  1175.     048E7H, 0000CH,          (*     MOVEM.L A4-A5, -(A7)    *)
  1176.     0200EH,                  (* G1: MOVE.L  A6, D0          *)
  1177.     06732H,                  (*     BEQ     G4              *)
  1178.     0286EH, 00004H,          (*     MOVE.L  0004(A6), A4    *)
  1179.     0508EH,                  (*     ADDQ.L  #8, A6          *)
  1180.     02E1EH,                  (* G2: MOVE.L  (A6)+, D7       *)
  1181.     06B20H,                  (*     BMI     G3              *)
  1182.     02034H, 07800H,          (*     MOVE.L  00(A4,D7.L), D0 *)
  1183.     067F6H,                  (*     BEQ     G2              *)
  1184.     02040H,                  (*     MOVE.L  D0, A0          *)
  1185.     008E8H, 7, -4,           (*     BSET    #07,  FFFC(A0)  *)
  1186.     066ECH,                  (*     BNE     G2              *)
  1187.     00828H, 0, -1,           (*     BTST    #00,  FFFF(A0)  *)
  1188.     066E4H                   (*     BNE     G2              *)
  1189.   ); (* INLINE *)
  1190.   Mark (SYS.REG (8));        (*     JSR     Kernel_Mark     *)
  1191.   SYS.INLINE (
  1192.     060DCH,                  (*     BRA     G2              *)
  1193.     -2239H,                  (* G3: ADD.L   D7, A6          *)
  1194.     0598EH,                  (*     SUBQ.L  #4, A6          *)
  1195.     02C56H,                  (*     MOVE.L  (A6), A6        *)
  1196.     060CAH,                  (*     BRA     G1              *)
  1197.     04CDFH, 03000H           (* G4: MOVEM.L (A7)+, A4-A5    *)
  1198.   ); (* INLINE *)
  1199.   Sweep;                     (*     BSR     Kernel_Sweep    *)
  1200. END GC;
  1201.  
  1202.  
  1203. (* InstallTrapHandler()
  1204. **
  1205. ** Installing a trap handler makes life difficult when using a debugger or
  1206. ** profiler, so this procedure is provided to allow the programmer to
  1207. ** decide if the trap handler should be installed or not.
  1208. *)
  1209.  
  1210. PROCEDURE InstallTrapHandler*;
  1211.   VAR t : LONGINT;
  1212. BEGIN (* InstallTrapHandler *)
  1213.   IF ~handlerInstalled THEN
  1214.     (* Allocate the traps recognised by the handler *)
  1215.  
  1216.     userTraps := {};
  1217.     FOR t := 0 TO 6 DO
  1218.       IF AllocTrap (t) >= 0 THEN INCL (userTraps, t)
  1219.       ELSE HALT (23)
  1220.       END
  1221.     END;
  1222.  
  1223.     (* Replace the existing trap handler with one of our own. *)
  1224.  
  1225.     oldTrapCode := process.trapCode;
  1226.     oldTrapData := process.trapData;
  1227.     process.trapCode := TrapHandler;
  1228.     process.trapData := NIL;
  1229.     handlerInstalled := TRUE
  1230.   END;
  1231. END InstallTrapHandler;
  1232.  
  1233.  
  1234. (*
  1235. ** RemoveTrapHandler()
  1236. **
  1237. ** Removes the trap handler.
  1238. *)
  1239.  
  1240. PROCEDURE RemoveTrapHandler*;
  1241.   VAR t : LONGINT;
  1242. BEGIN (* RemoveTrapHandler *)
  1243.   IF handlerInstalled THEN
  1244.     FOR t := 0 TO 6 DO IF t IN userTraps THEN FreeTrap (t) END END;
  1245.     process.trapCode := oldTrapCode;
  1246.     process.trapData := oldTrapData;
  1247.     handlerInstalled := FALSE
  1248.   END
  1249. END RemoveTrapHandler;
  1250.  
  1251.  
  1252. (*-----------------------------------------------------------------------**
  1253. ** This module initialisation is the first Oberon code executed by a     **
  1254. ** program. It is called from a short code prologue placed at the very   **
  1255. ** start of the program.                                                 **
  1256. **-----------------------------------------------------------------------*)
  1257.  
  1258. <*$ClearVars+*>
  1259. BEGIN (* Kernel *)
  1260.  
  1261.   (* Dos passes the command line and its length in A0/D0. These must be
  1262.   ** saved, as well as the initial stack pointer.
  1263.   *)
  1264.  
  1265.   SYS.GETREG (8, dosCmdBuf);
  1266.   SYS.GETREG (0, dosCmdLen);
  1267.   SYS.GETREG (15, initialSP);
  1268.   INC (initialSP, 4); (* Allow for the JSR that got us here. *)
  1269.  
  1270.   (* Get SysBase *)
  1271.   SYS.GET (AbsExecBase, SysBase);
  1272.  
  1273.   (* Now find our Process structure and see if we are run from the Shell
  1274.   ** or the Workbench.
  1275.   *)
  1276.   process := FindTask (NIL);
  1277.   fromWorkbench := (process.cli = NIL);
  1278.  
  1279.   IF fromWorkbench THEN
  1280.     (* The program was run by Workbench. We must wait for a startup
  1281.     ** message at the process message port and clear it immediately. The
  1282.     ** message must be saved, to be replied when the program exits.
  1283.     *)
  1284.     WaitPort (process.msgPort);
  1285.     WBenchMsg := GetMsg (process.msgPort);
  1286.   END;
  1287.  
  1288.   (* Attempt to open the math library. *)
  1289.  
  1290.   mathBase := OpenLibrary ("mathieeesingbas.library", 33);
  1291.   ASSERT (mathBase # NIL, 100);
  1292.  
  1293.   (* D1 is non-zero when the main body starts. It must be zero on exit *)
  1294.   SYS.SETREG (1, 0)
  1295. END Kernel.
  1296.  
  1297. (*************************************************************************
  1298.  
  1299.   $Log: Kernel.mod $
  1300.   Revision 1.5  1995/01/26  00:37:31  fjc
  1301.   - Release 1.5
  1302.  
  1303.   Revision 1.4  1995/01/09  18:25:03  fjc
  1304.   - Incorporated changes in interfaces
  1305.  
  1306.   Revision 1.3  1994/11/11  16:44:48  fjc
  1307.   - Uses new external code interface.
  1308.  
  1309.   Revision 1.2  1994/09/18  20:53:39  fjc
  1310.   - Converted switches to pragmas/options
  1311.  
  1312.   Revision 1.1  1994/08/22  21:50:29  fjc
  1313.   Initial revision
  1314.  
  1315. *************************************************************************)
  1316.